package com.youan.log.modules.audit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youan.log.modules.audit.entity.AttackAnalysis;
import com.youan.log.modules.audit.entity.AttackedAnalysis;
import com.youan.log.modules.audit.entity.EventRuleNum;
import com.youan.log.modules.audit.entity.RegionData;
import com.youan.log.modules.audit.mapper.RegionDataMapper;
import com.youan.log.modules.audit.service.IAttackAnalysisService;
import com.youan.log.modules.audit.service.IAttackedAnalysisService;
import com.youan.log.modules.audit.service.IEventRulenumService;
import com.youan.log.modules.audit.service.IRegionDataService;
import com.youan.log.modules.audit.vo.RegionDataVO;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author youan-autocode
 * @since 2021-03-04
 */
@Service
public class RegionDataServiceImpl extends ServiceImpl<RegionDataMapper, RegionData> implements IRegionDataService {

    @Autowired
    private RegionDataMapper regionDataMapper;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private IEventRulenumService eventRulenumService;
    @Autowired
    private IAttackAnalysisService attackAnalysisService;
    @Autowired
    private IAttackedAnalysisService attackedAnalysisService;

    private String[] ruleAboutAttack = {"10050001948","10050002295","10050002065","10050002066","10050001084","10050001476"};

    @Override
    public IPage<RegionDataVO> selectRegionData(IPage<RegionDataVO> page, RegionDataVO regionData) throws Exception {
        List<RegionDataVO> result = new ArrayList<>();
        String start = regionData.getStartTime();
        String end = regionData.getEndTime();

        String suffix = start.substring(0,10).replace("-","_");

        String startTime = start.substring(11);
        String endTime = end.substring(11);
        regionData.setStartTime(startTime);
        regionData.setEndTime(endTime);

        String tableName = "region_data_" + suffix;
        // 查询下表是否存在
        if(!tableExist(tableName)) {
            throw new Exception("数据库中不存在" + tableName + "的数据，请检查是否导入！");
        }
        if(StringUtils.isNotBlank(regionData.getRuleIds())) {
            regionData.setRuleList(Arrays.asList(regionData.getRuleIds().split(",")));
        }
        result = regionDataMapper.selectRegionData(page, tableName, regionData);
        return page.setRecords(buildRegionData(result, ""));
    }

    @Override
    public RegionData detail(Long id, String tableSuffix) {
        String sql = "SELECT * from ?  where id = ?";
        RegionData result = jdbcTemplate.queryForObject(sql, (resultSet, i) -> {
            RegionData regionData = new RegionData();
            regionData.setPayload(resultSet.getString("payload"));
            regionData.setLoginFailureAccount(resultSet.getString("login_failure_account"));
            return regionData;
        },id, "region_data" + tableSuffix);
        return result;
    }

    @Override
    public IPage<RegionDataVO> selectAttackAndAttackedRegionData(IPage<RegionDataVO> page, RegionDataVO regionData) throws Exception {

        RegionDataVO realRegionData = new RegionDataVO();

        String start = regionData.getStartTime();
        String end = regionData.getEndTime();

        String suffix = start.substring(0,10).replace("-","_");

        String startTime = start.substring(11);
        String endTime = end.substring(11);

        realRegionData.setStartTime(startTime);
        realRegionData.setEndTime(endTime);

        String tableName = "region_data_" + suffix;
        if(StringUtils.isBlank(regionData.getTargetIp())) {
            throw new Exception("IP字段为空，请输入想要查询的IP");
        }
        // 查询下表是否存在
        if(!tableExist(tableName)) {
            throw new Exception("数据库中不存在" + tableName + "的数据，请检查是否导入！");
        }


        String ruleIds = regionData.getRuleIds();
        List<String> ruleList;
        if(StringUtils.isBlank(ruleIds)) {
            realRegionData.setRuleList(Arrays.asList(ruleAboutAttack));
        }else {
            realRegionData.setRuleList(Arrays.asList(ruleIds.split(",")));
        }
        ruleList = realRegionData.getRuleList();

        if(StringUtils.isNotBlank(regionData.getAttackOrAttacked())) {
            if(regionData.getAttackOrAttacked().equals("attack")) {
                // 攻击者
                Map<String,Object> map = getAttackByAttackId(page, regionData, tableName, ruleList, start);
                List<RegionDataVO> result = (List<RegionDataVO>) map.get("result");
                Long total = Long.parseLong(map.get("total").toString());
                page.setRecords(result);
                page.setTotal(total);
                return page;
            }else if(regionData.getAttackOrAttacked().equals("attacked")) {
                // 被攻击者
                Map<String,Object> map = getAttackedByAttackedId(page, regionData, tableName, ruleList, start);
                List<RegionDataVO> result = (List<RegionDataVO>) map.get("result");
                Long total = Long.parseLong(map.get("total").toString());
                page.setRecords(result);
                page.setTotal(total);
                return page;
            }else {
                return page;
            }
        } else {
            // 全部 攻击和被攻击都要选择出来
            List<RegionDataVO> finalResult = new ArrayList<>();
            Map<String,Object> mapAttack = getAttackByAttackId(page, regionData, tableName, ruleList, start);
            List<RegionDataVO> resultAttack = (List<RegionDataVO>) mapAttack.get("result");
            Long totalAttack = Long.parseLong(mapAttack.get("total").toString());
            finalResult.addAll(resultAttack);
            Map<String,Object> mapAttacked = getAttackedByAttackedId(page, regionData, tableName, ruleList, start);
            List<RegionDataVO> resultAttacked = (List<RegionDataVO>) mapAttacked.get("result");
            Long totalAttacked = Long.parseLong(mapAttacked.get("total").toString());
            finalResult.addAll(resultAttacked);

            page.setTotal(totalAttacked + totalAttack);
            page.setRecords(finalResult);
            return page;
        }
    }

    private Map<String, Object> getAttackByAttackId(IPage<RegionDataVO> page, RegionDataVO regionData, String tableName, List<String> ruleList, String start) {
        List<RegionDataVO> result = new ArrayList<>();
        Map<String, Object> map = new HashMap();
        // 先要去攻击表里查看是否存在这个攻击ip，如果不存在就不需要继续查询了！因为不认为是一个攻击者
        if(StringUtils.isNotBlank(regionData.getTargetIp()) && !isAttcker(regionData.getTargetIp(), start.substring(0,10))) {
            map.put("total", 0);
            map.put("result", result);
            return map;
        }
        List<String> sourceRule = new ArrayList<>();
        List<String> destRule = new ArrayList<>();
        // 是否存在规则
        if(CollectionUtil.isNotEmpty(ruleList)) {
            if(ruleList.contains("10050001084")) {
                destRule.add("10050001084");
            }
            if(ruleList.contains("10050001476")) {
                destRule.add("10050001476");
            }
            if(ruleList.contains("10050001948")) {
                destRule.add("10050001948");
            }
            if(ruleList.contains("10050002295")) {
                sourceRule.add("10050002295");
            }
            if(ruleList.contains("10050002065")) {
                sourceRule.add("10050002065");
            }
            if(ruleList.contains("10050002066")) {
                sourceRule.add("10050002066");
            }
            result = getAttackOrAttackedByRule(page, regionData.getTargetIp(), tableName, sourceRule, destRule);
            Long total = getAttackOrAttackedByRuleCount(page, regionData.getTargetIp(), tableName, sourceRule, destRule);
            map.put("total", total);
            map.put("result", buildRegionData(result, "attack"));
            return map;

        }else {
            // 不存在及全部规则
            map.put("result", buildRegionData(regionDataMapper.getAllAttack(page,regionData.getTargetIp(), tableName), "attack"));
            map.put("total", page.getTotal());
            return map;
        }
    }

    private List<RegionDataVO> getAttackOrAttackedByRule(IPage<RegionDataVO> page, String targetIp, String tableName, List<String> sourceRule, List<String> destRule) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("select * from ").append(tableName);
        stringBuffer.append(" where 1=1 ");
        if(CollectionUtil.isNotEmpty(sourceRule) && CollectionUtil.isNotEmpty(destRule)) {
            stringBuffer.append("and (");

            stringBuffer.append(" rule_id in (");
            sourceRule.forEach(item -> {
                stringBuffer.append("'"+ item +"',");
            });
            stringBuffer.setLength(stringBuffer.length() - 1);
            stringBuffer.append(" )");
            stringBuffer.append(" and source_ip = '" + targetIp + "'");
            stringBuffer.append(")");
            stringBuffer.append(" union ");
            stringBuffer.append("select * from ").append(tableName);
            stringBuffer.append(" where 1=1 ");

            stringBuffer.append("and (");
            stringBuffer.append(" rule_id in (");
            destRule.forEach(item -> {
                stringBuffer.append("'"+ item +"',");
            });
            stringBuffer.setLength(stringBuffer.length() - 1);
            stringBuffer.append(" )");
            stringBuffer.append(" and destination_ip = '" + targetIp + "'");
            stringBuffer.append(")");

        }else if(CollectionUtil.isNotEmpty(sourceRule)) {
            stringBuffer.append(" and rule_id in (");
            sourceRule.forEach(item -> {
                stringBuffer.append("'"+ item +"',");
            });
            stringBuffer.setLength(stringBuffer.length() - 1);
            stringBuffer.append(" )");
            stringBuffer.append(" and source_ip = '" + targetIp + "'");
        }else {
            stringBuffer.append(" and rule_id in (");
            destRule.forEach(item -> {
                stringBuffer.append("'"+ item +"',");
            });
            stringBuffer.setLength(stringBuffer.length() - 1);
            stringBuffer.append(" )");
            stringBuffer.append(" and destination_ip = '" + targetIp + "'");
        }
        stringBuffer.append(" limit " + (page.getSize() * (page.getCurrent()-1)) + "," + page.getSize());
        return jdbcTemplate.query(stringBuffer.toString(),  new Object[]{}, new BeanPropertyRowMapper<RegionDataVO>(RegionDataVO.class));
    }

    private Long getAttackOrAttackedByRuleCount(IPage<RegionDataVO> page, String targetIp, String tableName, List<String> sourceRule, List<String> destRule) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("select count(1) as num from ").append(tableName);
        stringBuffer.append(" where 1=1 ");
        if(CollectionUtil.isNotEmpty(sourceRule) && CollectionUtil.isNotEmpty(destRule)) {
            if(CollectionUtil.isNotEmpty(sourceRule)) {
                stringBuffer.append("and ((");
                stringBuffer.append(" rule_id in (");
                sourceRule.forEach(item -> {
                    stringBuffer.append("'"+ item +"',");
                });
                stringBuffer.setLength(stringBuffer.length() - 1);
                stringBuffer.append(" )");
                stringBuffer.append(" and source_ip = '" + targetIp + "'");
                stringBuffer.append(")");
            }
            stringBuffer.append(" or ");
            if(CollectionUtil.isNotEmpty(destRule)) {
                stringBuffer.append("(");
                stringBuffer.append(" rule_id in (");
                destRule.forEach(item -> {
                    stringBuffer.append("'"+ item +"',");
                });
                stringBuffer.setLength(stringBuffer.length() - 1);
                stringBuffer.append(" )");
                stringBuffer.append(" and destination_ip = '" + targetIp + "'");
                stringBuffer.append("))");
            }
        }else if(CollectionUtil.isNotEmpty(sourceRule)) {
            stringBuffer.append(" and rule_id in (");
            sourceRule.forEach(item -> {
                stringBuffer.append("'"+ item +"',");
            });
            stringBuffer.setLength(stringBuffer.length() - 1);
            stringBuffer.append(" )");
            stringBuffer.append(" and source_ip = '" + targetIp + "'");
        }else {
            stringBuffer.append(" and rule_id in (");
            destRule.forEach(item -> {
                stringBuffer.append("'"+ item +"',");
            });
            stringBuffer.setLength(stringBuffer.length() - 1);
            stringBuffer.append(" )");
            stringBuffer.append(" and destination_ip = '" + targetIp + "'");
        }
        Long total = jdbcTemplate.queryForObject(stringBuffer.toString(), Long.class);
        return total;
    }


    private Map<String, Object> getAttackedByAttackedId(IPage<RegionDataVO> page, RegionDataVO regionData, String tableName, List<String> ruleList, String start) {
        Map<String, Object> map = new HashMap();
        List<RegionDataVO> result = new ArrayList<>();
        // 先要去被攻击表里查看是否存在这个攻击ip，如果不存在就不需要继续查询了！因为不认为是一个被攻击者
        if(StringUtils.isNotBlank(regionData.getTargetIp()) && !isAttckeder(regionData.getTargetIp(), start.substring(0,10))) {
            map.put("total", 0);
            map.put("result", result);
            return map;
        }
        List<String> sourceRule = new ArrayList<>();
        List<String> destRule = new ArrayList<>();

        if(CollectionUtil.isNotEmpty(ruleList)) {
            if(ruleList.contains("10050001476")) {
                sourceRule.add("10050001476");
            }
            if(ruleList.contains("10050001084")) {
                sourceRule.add("10050001084");
            }
            if(ruleList.contains("10050001948")) {
                sourceRule.add("10050001948");
            }
            if(ruleList.contains("10050002295")) {
                destRule.add("10050002295");
            }
            if(ruleList.contains("10050002065")) {
                destRule.add("10050002065");
            }
            if(ruleList.contains("10050002066")) {
                destRule.add("10050002066");
            }
            result = getAttackOrAttackedByRule(page, regionData.getTargetIp(), tableName, sourceRule, destRule);
            Long total = getAttackOrAttackedByRuleCount(page, regionData.getTargetIp(), tableName, sourceRule, destRule);
            map.put("total", total);
            map.put("result", buildRegionData(result, "attacked"));
            return map;
        }else {
            // 不存在及全部规则
            map.put("result", buildRegionData(regionDataMapper.getAllAttacked(page,regionData.getTargetIp(), tableName), "attacked"));
            map.put("total", page.getTotal());
            return map;
        }
    }

    private boolean isAttckeder(String ip, String date) {
        LambdaQueryWrapper<AttackedAnalysis> attackedAnalysisLqw = new LambdaQueryWrapper<AttackedAnalysis>()
                .eq(AttackedAnalysis::getAttackedIp,ip).eq(AttackedAnalysis::getDate, date);
        List<AttackedAnalysis> attackedAnalysisList = attackedAnalysisService.list(attackedAnalysisLqw);
        if(CollectionUtil.isEmpty(attackedAnalysisList)) {
            return false;
        }
        return true;
    }

    private boolean isAttcker(String ip, String date) {
        LambdaQueryWrapper<AttackAnalysis> attackAnalysisLqw = new LambdaQueryWrapper<AttackAnalysis>()
                .eq(AttackAnalysis::getAttackerIp,ip).eq(AttackAnalysis::getDate, date);
        List<AttackAnalysis> attackAnalysisList = attackAnalysisService.list(attackAnalysisLqw);
        if(CollectionUtil.isEmpty(attackAnalysisList)) {
            return false;
        }
        return true;
    }

    private List<RegionDataVO> buildRegionData(List<RegionDataVO> result, String attackOrAttacked) {
        result.forEach(item -> {
            if(StringUtils.isNotBlank(item.getRuleId())) {
                LambdaQueryWrapper<EventRuleNum> eventRuleNumLqw = new LambdaQueryWrapper<EventRuleNum>()
                        .eq(EventRuleNum::getRuleId, item.getRuleId());
                EventRuleNum eventRuleNum = eventRulenumService.getOne(eventRuleNumLqw);
                if(eventRuleNum != null) {
                    item.setRuleName(eventRuleNum.getRuleName());
                }
            }
            if(StringUtils.isNotBlank(item.getDirection())) {
                item.setDirectionName(item.getDirection().equals("s")?"源ip归属山东":"目的ip归属山东");
            }
            item.setDatetime(item.getDate() + " " + item.getTime());
            if(StringUtils.isNotBlank(attackOrAttacked)) {
                item.setAttackOrAttacked(attackOrAttacked);
            }
        });
        return result;
    }

    private boolean tableExist(String tableName) {
        String sql = "SELECT table_name FROM information_schema.TABLES WHERE table_name = ?";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, tableName);
        if(CollectionUtil.isNotEmpty(list)) {
            return true;
        }
        return false;
    }
}
